#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import shutil
import json
import platform
import sys
import subprocess
from driver import Initializer
from driver import Builder
from util import *
from option import Options
from string import Template


class Initializer_cpp(Initializer):
    def __init__(self, options):
        self.options = options

    def check(self):
        if not os.path.exists("repo.init"):
            return self.init()
        else:
            return True

    def build_backend(self):
        os.chdir("rpc-backend-cpp")
        file = open("CMakeLists.txt", "w")
        file.write("cmake_minimum_required(VERSION 3.5)\n")
        if platform.system() == "Windows":
            file.write("set(CMAKE_CXX_STANDARD 17)\n")
        file.write("project (rpc-backend-cpp)\n")
        file.write("SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib/root)\n")
        file.write('INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/coroutine)\n')
        if platform.system() == "Windows":
            file.write(
                'set(SRC_LIST src/rpc.cpp src/rpc_proxy.cpp src/rpc_logger.cpp src/rpc_stub.cpp '
                'src/rpc_statistics_impl.cpp src/coroutine/detail/timer.cpp src/coroutine/detail/coro_call.cpp '
                'src/coroutine/windows/coroutine.cpp)\n')
        else:
            file.write(
                'set(SRC_LIST src/rpc.cpp src/rpc_proxy.cpp src/rpc_logger.cpp src/rpc_stub.cpp '
                'src/rpc_statistics_impl.cpp src/coroutine/detail/timer.cpp src/coroutine/detail/coro_call.cpp '
                'src/coroutine/linux/coroutine.cpp)\n')
        file.write('add_library(rpc ${SRC_LIST})\n')
        file.write('SET_TARGET_PROPERTIES(rpc PROPERTIES PREFIX "lib")\n')
        file.write('SET_TARGET_PROPERTIES(rpc PROPERTIES SUFFIX ".a")\n')

        file.write('target_compile_definitions(rpc PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n\n)\n')

        file.write("IF (MSVC)\n")
        file.write(
            'set_target_properties(rpc PROPERTIES COMPILE_FLAGS "/EHa /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 '
            '/wd4065")\n')
        file.write('    foreach(var\n')
        file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
        file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
        file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
        file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
        file.write('    )\n')
        file.write('        if(${var} MATCHES "/MD")\n')
        file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
        file.write('        endif()\n')
        file.write('    endforeach()\n')
        file.write("ELSE()\n")
        file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fpermissive -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
        file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fpermissive -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
        file.write('    endif()\n')
        file.write("ENDIF ()\n")
        file.close()
        if platform.system() == "Windows":
            os.system('cmake -G  "Visual Studio 16 2019" -A x64')
            os.system('cmake --build . --config "Release"')
            os.system('cmake --build . --config "Debug"')
        else:
            os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
            os.system("make")
        shutil.copyfile("src/cppgen.py", "../../bin/cppgen.py")
        shutil.copyfile("src/cppgen_pb_layer.py", "../../bin/cppgen_pb_layer.py")
        shutil.copyfile("src/cppgen_sdk.py", "../../bin/cppgen_sdk.py")
        shutil.copyfile("src/rpc_root.h", "../../src/include/root/rpc_root.h")
        shutil.copyfile("src/object_pool.h", "../../src/include/root/object_pool.h")
        shutil.copyfile("src/rpc_defines.h", "../../src/include/root/rpc_defines.h")
        shutil.copyfile("src/rpc_logger.h", "../../src/include/root/rpc_logger.h")
        shutil.copyfile("src/rpc_proxy.h", "../../src/include/root/rpc_proxy.h")
        shutil.copyfile("src/rpc_service.h", "../../src/include/root/rpc_service.h")
        shutil.copyfile("src/rpc_singleton.h", "../../src/include/root/rpc_singleton.h")
        shutil.copyfile("src/rpc_stub.h", "../../src/include/root/rpc_stub.h")
        shutil.copyfile("src/rpc_transport.h", "../../src/include/root/rpc_transport.h")
        shutil.copyfile("src/rpc_statistics.hh", "../../src/include/root/rpc_statistics.hh")
        shutil.copyfile("src/coroutine/coroutine.h", "../../src/include/root/coroutine/coroutine.h")
        shutil.copyfile("src/coroutine/detail/list.h", "../../src/include/root/coroutine/detail/list.h")
        shutil.copyfile("src/coroutine/detail/timer.h", "../../src/include/root/coroutine/detail/timer.h")
        shutil.copyfile("src/rpc_interface_descriptor.hh", "../../src/include/root/rpc_interface_descriptor.hh")
        shutil.copyfile("src/rpc_probe.h", "../../src/include/root/rpc_probe.h")
        if platform.system() == "Windows":
            shutil.copyfile("src/coroutine/windows/coroutine.h", "../../src/include/root/coroutine/windows/coroutine.h")
        else:
            shutil.copyfile("src/coroutine/linux/coroutine.h", "../../src/include/root/coroutine/linux/coroutine.h")
        os.chdir("..")

    def inspectpath(self):
        if not os.path.exists("tmp"):
            os.mkdir("tmp")
        if not os.path.exists("bin"):
            os.mkdir("bin")
        if not os.path.exists("usr/impl"):
            os.makedirs("usr/impl")
        if not os.path.exists("lib/root"):
            os.makedirs("lib/root")
        if not os.path.exists("lib/proxy"):
            os.makedirs("lib/proxy")
        if not os.path.exists("lib/stub"):
            os.makedirs("lib/stub")
        if not os.path.exists("src/idl"):
            os.makedirs("src/idl")
        if not os.path.exists("src/include/root/coroutine/detail"):
            os.makedirs("src/include/root/coroutine/detail")
        if platform.system() == "Windows":
            if not os.path.exists("src/include/root/coroutine/windows"):
                os.makedirs("src/include/root/coroutine/windows")
        else:
            if not os.path.exists("src/include/root/coroutine/linux"):
                os.makedirs("src/include/root/coroutine/linux")
        if not os.path.exists("src/proxy"):
            os.makedirs("src/proxy")
        if not os.path.exists("src/stub"):
            os.makedirs("src/stub")


    def init(self):
        print("Initializing repo...")
        if not Initializer.checkPrecondition(self):
            return False

        self.inspectpath()

        if os.path.exists("tmp"):
            os.chdir("tmp")
        if os.path.exists("rpc-frontend"):
            os.chdir("rpc-frontend")
            if os.system('git pull origin') != 0:
                return False
            os.chdir("..")
        else:
            if os.system("git clone https://gitee.com/dennis-kk/rpc-frontend") != 0:
                print("git clone https://gitee.com/dennis-kk/rpc-frontend failed")
                return False
        self.build_frontend()
        os.chdir("..")
        os.chdir("tmp")
        if os.path.exists("rpc-backend-cpp"):
            os.chdir("rpc-backend-cpp")
            if os.system('git pull origin') != 0:
                return False
            os.chdir("..")
        else:
            if os.system("git clone https://gitee.com/dennis-kk/rpc-backend-cpp") != 0:
                print("git clone https://gitee.com/dennis-kk/rpc-backend-cpp failed")
                return False
        self.build_backend()
        os.chdir("..")
        open("repo.init", "w+").close()
        return True

    def checkEnv(self):
        os.system("protoc --version")
        os.system("git --version")
        os.system("cmake --version")
        if platform.system() == "Linux":
            if os.system("gcc --version") != 0:
                os.system("clang --version")
        else:
            print("Visual Studio 16 2019")


class Builder_cpp(Builder):
    def __init__(self, options):
        Builder.__init__(self, options)

    def list_all_dir(self, rootdir):
        _dirs = []
        list = os.listdir(rootdir)
        for i in range(0, len(list)):
            path = rootdir + '/' + list[i]
            if os.path.isdir(path):
                _dirs.append(path)
                _dirs.extend(self.list_all_dir(path))
        return _dirs
        
    def build_sdk(self, name, sname=None):
        idl_name = self.check_idl_name(name)
        if not os.path.exists("src/idl/" + idl_name):
            print (name + " not found in repo.")
            return
        (base_name, _) = os.path.splitext(os.path.basename(idl_name))
        if not os.path.exists("tmp/" + base_name + "/proxy"):
            os.makedirs("tmp/" + base_name + "/proxy")
        if not os.path.exists("tmp/" + base_name + "/stub"):
            os.makedirs("tmp/" + base_name + "/stub")
        if not os.path.exists("lib/" + base_name):
            os.makedirs("lib/" + base_name)
        if not os.path.exists("lib/proxy/" + base_name):
            os.makedirs("lib/proxy/" + base_name)
        if not os.path.exists("lib/stub/" + base_name):
            os.makedirs("lib/stub/" + base_name)
        json_str = json.load(open("src/idl/" + base_name + ".idl.cpp.json"))
        if json_str["serviceNames"] :
            for service_name in json_str["serviceNames"]:
                if not os.path.exists("tmp/" + base_name + "/proxy/" + service_name):
                    os.makedirs("tmp/" + base_name + "/proxy/" + service_name)
                if not os.path.exists("tmp/" + base_name + "/stub/" + service_name):
                    os.makedirs("tmp/" + base_name + "/stub/" + service_name)

        os.chdir("tmp/" + base_name)
        file = open("CMakeLists.txt", "w")
        file.write("cmake_minimum_required(VERSION 3.5)\n")
        if platform.system() == "Windows":
            file.write("set(CMAKE_CXX_STANDARD 17)\n")
        file.write("project (common_pb_layer)\n")
        file.write("SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib/" + base_name + ")\n")
        file.write(
            'set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../src/' + base_name + '/protobuf/' + base_name + '.service.pb.cc)\n')
        file.write('add_library(' + base_name + ' ${SRC_LIST})\n\n')
        file.write("SET_TARGET_PROPERTIES(" + base_name + ' PROPERTIES PREFIX "lib")\n')
        file.write("SET_TARGET_PROPERTIES(" + base_name + ' PROPERTIES SUFFIX ".a")\n')

        file.write("target_include_directories(" + base_name + " PUBLIC")
        file.write("    ${PROJECT_SOURCE_DIR}/../../src/include/"+base_name+"/protobuf ${PROJECT_SOURCE_DIR}/../../thirdparty/include ")
        file.write(")\n")

        file.write("IF (MSVC)\n")
        file.write(
            '    set_target_properties(' + base_name + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 /wd4065 /wd4250")\n')
        file.write('    foreach(var\n')
        file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
        file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
        file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
        file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
        file.write('    )\n')
        file.write('        if(${var} MATCHES "/MD")\n')
        file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
        file.write('        endif()\n')
        file.write('    endforeach()\n')
        file.write("ELSE()\n")
        file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fnon-call-exceptions -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
        file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fnon-call-exceptions -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
        file.write('    endif()\n')
        file.write("ENDIF ()\n")
        
        file.close()
        if platform.system() == "Windows":
            os.system('cmake -G  "Visual Studio 16 2019" -A x64')
            os.system('cmake --build . --config "Release"')
            os.system('cmake --build . --config "Debug"')
        else:
            os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
            os.system("make")
        all_proxy_a_path = []
        all_proxy_a_path_debug = []
        all_proxy_a_path_release = []

        if json_has_attr(json_str, "services"):
            for service in json_str["services"]:
                if sname is not None:
                    if sname != service["name"]:
                        continue
                os.chdir("proxy/" + service["name"])
                file = open("CMakeLists.txt", "w")
                file.write("cmake_minimum_required(VERSION 3.5)\n")
                if platform.system() == "Windows":
                    file.write("set(CMAKE_CXX_STANDARD 17)\n")
                file.write("project (service_proxy_sdk)\n")
                
                file.write(
                    "SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../../lib/proxy/" + base_name + "/" + service[
                        "name"] + ")\n")
                all_proxy_a_path_debug.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/Debug/lib' +
                    service["name"] + '_proxy.a')
                all_proxy_a_path_release.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/Release/lib' +
                    service["name"] + '_proxy.a')
                all_proxy_a_path.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/lib' + service[
                        "name"] + '_proxy.a')
                file.write(
                    'INCLUDE_DIRECTORIES(/usr/include/ ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + ' ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/' +
                    service[
                        "name"] + '/proxy ${PROJECT_SOURCE_DIR}/../../../../src/include/root ${PROJECT_SOURCE_DIR}/../../../../src/include/root/coroutine ' + '${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/protobuf\n ${PROJECT_SOURCE_DIR}/../../../../thirdparty/include)\n')
                file.write('set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../../../src/proxy/' + base_name + '/' + service[
                    "name"] + '/' + base_name + '.service.' + service[
                            "name"] + '.proxy.sdk.cpp ' + '${PROJECT_SOURCE_DIR}/../../../../src/proxy/' + base_name + '/' +
                        service["name"] + '/' + base_name + '.service.' + service[
                            "name"] + '.proxy.serializer.cpp' + ')\n')
                file.write('add_library(' + service["name"] + '_proxy ' + ' SHARED ${SRC_LIST})\n\n')
                file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_proxy ' + ' PROPERTIES PREFIX "sdk")\n')
                file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_proxy ' + ' PROPERTIES SUFFIX ".so")\n')
                file.write('target_compile_definitions({service_name}_proxy PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n)\n'.format(service_name=service["name"]))
                file.write("IF (MSVC)\n")
                file.write('    set_target_properties(' + service[
                    "name"] + '_proxy ' + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 /wd4065 /wd4250")\n')
                file.write('    foreach(var\n')
                file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
                file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
                file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
                file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
                file.write('        )\n')
                file.write('        if(${var} MATCHES "/MD")\n')
                file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
                file.write('        endif()\n')
                file.write('    endforeach()\n')
                file.write("ELSE()\n")
                file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
                file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                    "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
                file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
                file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                    "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
                file.write('    endif()\n')
                file.write("ENDIF ()\n")
                if platform.system() == "Windows":
                    file.write('target_link_libraries(' + service["name"] + '_proxy PUBLIC \n')
                    file.write(
                        '"$<$<AND:$<CONFIG:Release>,$<BOOL:${USR_LINK_RELEASE_LIB}>>:${USR_LINK_RELEASE_LIB}>"\n"$<$<AND:$<CONFIG:Debug>,$<BOOL:${USR_DEBUG_LINK_LIB}>>:${USR_DEBUG_LINK_LIB}>"\n' +
                        'debug ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/debug/libprotobufd.lib optimized ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/release/libprotobuf.lib\n'
                        'debug ${PROJECT_SOURCE_DIR}/../../../../lib/root/debug/librpc.a optimized ${PROJECT_SOURCE_DIR}/../../../../lib/root/release/librpc.a\n'
                        'debug ${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/debug/lib'+base_name+'.a optimized ${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/release/lib'+base_name+'.a\n'
                        )
                else:
                    file.write('target_link_libraries(' + service["name"] + '_proxy PUBLIC \n')
                    file.write(
                        '\t"$<$<BOOL:${USR_LINK_LIB}>:${USR_LINK_LIB}>"\n' + 
                        '\t${PROJECT_SOURCE_DIR}/../../../../lib/root/librpc.a\n' +
                        '\t${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/lib'+base_name+'.a\n' +
                        '\t${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/linux/libprotobuf.a\n'
                    )
                file.write(')\n')
                file.close()
                if platform.system() == "Windows":
                    os.system('cmake -G  "Visual Studio 16 2019" -A x64')
                    os.system('cmake --build . --config "Release"')
                    os.system('cmake --build . --config "Debug"')
                else:
                    os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
                    os.system("make")
                os.chdir("../../")
        os.chdir("../../")

    def build_idl(self, name, sname=None):
        idl_name = self.check_idl_name(name)
        if not os.path.exists("src/idl/" + idl_name):
            print (name + " not found in repo.")
            return
        (base_name, _) = os.path.splitext(os.path.basename(idl_name))
        if not os.path.exists("tmp/" + base_name + "/proxy"):
            os.makedirs("tmp/" + base_name + "/proxy")
        if not os.path.exists("tmp/" + base_name + "/stub"):
            os.makedirs("tmp/" + base_name + "/stub")
        if not os.path.exists("lib/" + base_name):
            os.makedirs("lib/" + base_name)
        if not os.path.exists("lib/proxy/" + base_name):
            os.makedirs("lib/proxy/" + base_name)
        if not os.path.exists("lib/stub/" + base_name):
            os.makedirs("lib/stub/" + base_name)
        json_str = json.load(open("src/idl/" + base_name + ".idl.cpp.json"))
        if json_str["serviceNames"] :
            for service_name in json_str["serviceNames"]:
                if not os.path.exists("tmp/" + base_name + "/proxy/" + service_name):
                    os.makedirs("tmp/" + base_name + "/proxy/" + service_name)
                if not os.path.exists("tmp/" + base_name + "/stub/" + service_name):
                    os.makedirs("tmp/" + base_name + "/stub/" + service_name)

        os.chdir("tmp/" + base_name)
        file = open("CMakeLists.txt", "w")
        file.write("cmake_minimum_required(VERSION 3.5)\n")
        if platform.system() == "Windows":
            file.write("set(CMAKE_CXX_STANDARD 17)\n")
        file.write("project (common_pb_layer)\n")
        file.write("SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib/" + base_name + ")\n")
        file.write(
            'set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../src/' + base_name + '/protobuf/' + base_name + '.service.pb.cc)\n')
        file.write('add_library(' + base_name + ' ${SRC_LIST})\n\n')
        file.write("SET_TARGET_PROPERTIES(" + base_name + ' PROPERTIES PREFIX "lib")\n')
        file.write("SET_TARGET_PROPERTIES(" + base_name + ' PROPERTIES SUFFIX ".a")\n')

        file.write("target_include_directories(" + base_name + " PUBLIC")
        file.write("    ${PROJECT_SOURCE_DIR}/../../src/include/"+base_name+"/protobuf ${PROJECT_SOURCE_DIR}/../../thirdparty/include ")
        file.write(")\n")

        file.write("IF (MSVC)\n")
        file.write(
            '    set_target_properties(' + base_name + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 /wd4065 /wd4250")\n')
        file.write('    foreach(var\n')
        file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
        file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
        file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
        file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
        file.write('    )\n')
        file.write('        if(${var} MATCHES "/MD")\n')
        file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
        file.write('        endif()\n')
        file.write('    endforeach()\n')
        file.write("ELSE()\n")
        file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fnon-call-exceptions -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
        file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
        file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                             "machine") + ' -g -O2 -std=c++17 -Wall -fnon-call-exceptions -fPIC")\n')
        file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
        file.write('    endif()\n')
        file.write("ENDIF ()\n")
        file.close()
        if platform.system() == "Windows":
            os.system('cmake -G  "Visual Studio 16 2019" -A x64')
            os.system('cmake --build . --config "Release"')
            os.system('cmake --build . --config "Debug"')
        else:
            os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
            os.system("make")
        all_proxy_a_path = []
        all_proxy_a_path_debug = []
        all_proxy_a_path_release = []

        if json_has_attr(json_str, "services"):
            for service in json_str["services"]:
                if sname is not None:
                    if sname != service["name"]:
                        continue
                os.chdir("proxy/" + service["name"])
                file = open("CMakeLists.txt", "w")
                file.write("cmake_minimum_required(VERSION 3.5)\n")
                if platform.system() == "Windows":
                    file.write("set(CMAKE_CXX_STANDARD 17)\n")
                file.write("project (service_proxy)\n")
                
                file.write(
                    "SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../../lib/proxy/" + base_name + "/" + service[
                        "name"] + ")\n")
                all_proxy_a_path_debug.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/Debug/lib' +
                    service["name"] + '_proxy.a')
                all_proxy_a_path_release.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/Release/lib' +
                    service["name"] + '_proxy.a')
                all_proxy_a_path.append(
                    '${PROJECT_SOURCE_DIR}/../../../../lib/proxy/' + base_name + "/" + service["name"] + '/lib' + service[
                        "name"] + '_proxy.a')
                file.write(
                    'INCLUDE_DIRECTORIES(/usr/include/ ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + ' ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/' +
                    service[
                        "name"] + '/proxy ${PROJECT_SOURCE_DIR}/../../../../src/include/root ${PROJECT_SOURCE_DIR}/../../../../src/include/root/coroutine ' + '${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/protobuf\n ${PROJECT_SOURCE_DIR}/../../../../thirdparty/include)\n')
                file.write('set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../../../src/proxy/' + base_name + '/' + service[
                    "name"] + '/' + base_name + '.service.' + service[
                            "name"] + '.proxy.cpp ' + '${PROJECT_SOURCE_DIR}/../../../../src/proxy/' + base_name + '/' +
                        service["name"] + '/' + base_name + '.service.' + service[
                            "name"] + '.proxy.serializer.cpp' + ')\n')
                file.write('add_library(' + service["name"] + '_proxy ' + ' ${SRC_LIST})\n\n')
                file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_proxy ' + ' PROPERTIES PREFIX "lib")\n')
                file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_proxy ' + ' PROPERTIES SUFFIX ".a")\n')
                file.write('target_compile_definitions({service_name}_proxy PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n)\n'.format(service_name=service["name"]))
                file.write("IF (MSVC)\n")
                file.write('    set_target_properties(' + service[
                    "name"] + '_proxy ' + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 /wd4065 /wd4250")\n')
                file.write('    foreach(var\n')
                file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
                file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
                file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
                file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
                file.write('        )\n')
                file.write('        if(${var} MATCHES "/MD")\n')
                file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
                file.write('        endif()\n')
                file.write('    endforeach()\n')
                file.write("ELSE()\n")
                file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
                file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                    "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
                file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
                file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                    "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
                file.write('    endif()\n')
                file.write("ENDIF ()\n")
                file.close()
                if platform.system() == "Windows":
                    os.system('cmake -G  "Visual Studio 16 2019" -A x64')
                    os.system('cmake --build . --config "Release"')
                    os.system('cmake --build . --config "Debug"')
                else:
                    os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
                    os.system("make")
                os.chdir("../../")

        if json_has_attr(json_str, "services"):
            for service in json_str["services"]:
                if sname is not None:
                    if sname != service["name"]:
                        continue
                os.chdir("stub/" + service["name"])
                if self.options.get_option("cpp", "custom_cmake") == "true":
                    if not os.path.exists("default"):
                        os.makedirs("default")
                    os.chdir("default")
                    file = open("CMakeLists.txt", "w")
                    file.write("cmake_minimum_required(VERSION 3.10)\n")
                    if platform.system() == "Windows":
                        file.write("set(CMAKE_CXX_STANDARD 17)\n")
                    file.write("project (service_stub)\n")

                    file.write('include(${PROJECT_SOURCE_DIR}/../../../../usr/impl/' + base_name+'/' + service["name"] + '/CMakeLists.txt)\n')

                    file.write("SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../../../lib/stub/" + base_name + "/" +
                            service["name"] + ")\n")
                    file.write(
                        'INCLUDE_DIRECTORIES(/usr/include/ ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + ' ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/' +
                        service[
                            "name"] + '/stub ${PROJECT_SOURCE_DIR}/../../../../src/include ${PROJECT_SOURCE_DIR}/../../../../src/include/root ${PROJECT_SOURCE_DIR}/../../../../src/include/root/coroutine ' + '${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/protobuf/  ${PROJECT_SOURCE_DIR}/../../../../thirdparty/include ' + ')\n'
                        )
                    file.write('set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../../../../src/stub/' + base_name + '/' + service[
                        "name"] + '/' + base_name + '.service.' + service[
                                "name"] + '.stub.cpp ' + '${PROJECT_SOURCE_DIR}/../../../../../src/stub/' + base_name + '/' +
                            service["name"] + '/' + base_name + '.service.' + service[
                                "name"] + '.stub.serializer.cpp' + ')\n')

                    file.write('add_library(' + service["name"] + '_stub ' + ' ${SRC_LIST})\n\n')

                    #
                    file.write('if (DEFINED USR_INCLUDE_DIR)\n')
                    file.write('target_include_directories('+service["name"]+'_stub PUBLIC\n\t${USR_INCLUDE_DIR}\n)\nendif()\n')

                    file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_stub ' + ' PROPERTIES PREFIX "lib")\n')
                    file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_stub ' + ' PROPERTIES SUFFIX ".a")\n')
                    file.write('target_compile_definitions({service_name}_stub PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n)\n'.format(service_name=service["name"]))
                    file.write("IF (MSVC)\n")
                    file.write('    set_target_properties(' + service[
                        "name"] + '_stub ' + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4311 /wd4302 /wd4312 /wd4244 /wd4065 /wd4250")\n')
                    file.write('    foreach(var\n')
                    file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
                    file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
                    file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
                    file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
                    file.write('        )\n')
                    file.write('        if(${var} MATCHES "/MD")\n')
                    file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
                    file.write('        endif()\n')
                    file.write('    endforeach()\n')
                    file.write("ELSE()\n")
                    file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
                    file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                        "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                    file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
                    file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
                    file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                        "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                    file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
                    file.write('    endif()\n')
                    file.write("ENDIF ()\n")
                    file.close()
                    if platform.system() == "Windows":
                        os.system('cmake -G  "Visual Studio 16 2019" -A x64')
                        os.system('cmake --build . --config "Release"')
                        os.system('cmake --build . --config "Debug"')
                    else:
                        os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
                        os.system("make")
                    os.chdir("..")
                    if os.path.exists("CMakeLists.txt"):
                        os.system("cmake -DCMAKE_C_COMPILER=gcc  -DCMAKE_CXX_COMPILER=g++ .")
                        os.system("make")
                    else:
                        print ("User given CMakeLists.txt not found for service: " + service["name"])
                else:
                    file = open("CMakeLists.txt", "w")
                    file.write("cmake_minimum_required(VERSION 3.10)\n")
                    if platform.system() == "Windows":
                        file.write("set(CMAKE_CXX_STANDARD 17)\n")
                    file.write("project (service_stub)\n")
                    file.write('include(${PROJECT_SOURCE_DIR}/../../../../usr/impl/' + base_name+'/' + service["name"] + '/CMakeLists.txt)\n')
                    
                    file.write(
                        "SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../../lib/stub/" + base_name + "/" + service[
                            "name"] + ")\n")
                    file.write(
                        'INCLUDE_DIRECTORIES(/usr/include/'+ ' ${PROJECT_SOURCE_DIR}/../../../../thirdparty/include' +' ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + ' ${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/' +
                        service["name"] + '/stub ${PROJECT_SOURCE_DIR}/../../../../src/include ${PROJECT_SOURCE_DIR}/../../../../src/include/root ${PROJECT_SOURCE_DIR}/../../../../src/include/root/coroutine ' + '${PROJECT_SOURCE_DIR}/../../../../src/include/' + base_name + '/protobuf/  ${PROJECT_SOURCE_DIR}/../../../../../ ' + ' ${PROJECT_SOURCE_DIR}/../../../../../../thirdparty/include ' + ')\n')
                    file.write('set(SRC_LIST ${PROJECT_SOURCE_DIR}/../../../../src/stub/' + base_name + '/' + service[
                        "name"] + '/' + base_name + '.service.' + service[
                                "name"] + '.stub.cpp ' + '${PROJECT_SOURCE_DIR}/../../../../src/stub/' + base_name + '/' +
                            service["name"] + '/' + base_name + '.service.' + service[
                                "name"] + '.stub.serializer.cpp' + ')\n')
                    file.write('add_library(' + service["name"] + '_stub ' + ' ${SRC_LIST})\n\n')
                    if service["loadType"] == "dynamic":
                        file.write('add_library(' + service["name"] + '_module SHARED ' + ' ${SRC_LIST})\n\n')

                    file.write('if (DEFINED USR_INCLUDE_DIR)\n')
                    file.write('target_include_directories('+service["name"]+'_stub PUBLIC\n\t${USR_INCLUDE_DIR}\n)\nendif()\n')
                    file.write('target_compile_definitions({service_name}_stub PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n)\n'.format(service_name=service["name"]))
                    if service["loadType"] == "dynamic":
                        file.write('if (DEFINED USR_INCLUDE_DIR)\n')                    
                        file.write('target_include_directories('+service["name"]+'_module PUBLIC\n\t${USR_INCLUDE_DIR}\n)\nendif()\n')
                        file.write('target_compile_definitions({service_name}_module PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG -DMODULE_EXPORT>\n$<$<CONFIG:Release>: -DRELEASE -DMODULE_EXPORT>\n)\n'.format(service_name=service["name"]))

                    file.write("IF (MSVC)\n")
                    file.write('    set_target_properties(' + service[
                        "name"] + '_stub ' + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4065 /wd4250")\n')
                    if service["loadType"] == "dynamic":
                        file.write('    set_target_properties(' + service[
                            "name"] + '_module ' + ' PROPERTIES COMPILE_FLAGS "/EHa /bigobj /wd4267 /wd4065 /wd4250")\n')
                    file.write('    foreach(var\n')
                    file.write('        CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE\n')
                    file.write('        CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO\n')
                    file.write('        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n')
                    file.write('        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO\n')
                    file.write('        )\n')
                    file.write('        if(${var} MATCHES "/MD")\n')
                    file.write('            string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")\n')
                    file.write('        endif()\n')
                    file.write('    endforeach()\n')
                    file.write("ELSE()\n")
                    file.write('    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")\n')
                    file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                        "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                    file.write('        set(CMAKE_CXX_COMPILER "clang++")\n')
                    file.write('    elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")\n')
                    file.write('        SET(CMAKE_CXX_FLAGS "' + self.options.get_option("cpp",
                                                                                        "machine") + ' -g -O2 -std=c++17 -Wall -Wno-deprecated-declarations -fnon-call-exceptions -fPIC")\n')
                    file.write('        set(CMAKE_CXX_COMPILER "g++")\n')
                    file.write('    endif()\n')
                    file.write("ENDIF ()\n")
                    file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_stub ' + ' PROPERTIES PREFIX "lib")\n')
                    file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_stub ' + ' PROPERTIES SUFFIX ".a")\n')
                    if service["loadType"] == "dynamic":
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_module ' + ' PROPERTIES PREFIX "lib")\n')
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + '_module ' + ' PROPERTIES SUFFIX ".so")\n')


                    file.write('set(SERVICE_SRC_LIST ${USR_IMPL_SRC})\n')
                    if service["loadType"] == "dynamic":
                        file.write('list(APPEND SERVICE_SRC_LIST ${PROJECT_SOURCE_DIR}/../../../../src/stub/' + base_name + '/' + service[
                            "name"] + '/' + base_name + '.service.' + service["name"] + '.so.cpp)\n\n')
                        file.write('if (DEFINED USR_LINK_DIR)\n')
                        file.write('link_directories(${USR_LINK_DIR})\n')
                        file.write('endif()\n\n')

                        file.write("add_library(" + service["name"] + ' SHARED ${SERVICE_SRC_LIST})\n\n')
                        file.write("IF (MSVC)\n")
                        file.write('    set_target_properties(' + service["name"] + ' PROPERTIES COMPILE_FLAGS "/EHa")\n')
                        file.write('ENDIF ()\n')
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + ' PROPERTIES PREFIX "lib")\n')
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + ' PROPERTIES SUFFIX ".so")\n')

                    else:

                        file.write('add_library(' + service["name"] + ' ${SERVICE_SRC_LIST})\n\n')
                        file.write("IF (MSVC)\n")
                        file.write('    set_target_properties(' + service["name"] + ' PROPERTIES COMPILE_FLAGS "/EHa")\n')
                        file.write('ENDIF ()\n')
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + ' PROPERTIES PREFIX "lib")\n')
                        file.write("SET_TARGET_PROPERTIES(" + service["name"] + ' PROPERTIES SUFFIX ".a")\n')

                    file.write('if (DEFINED USR_INCLUDE_DIR)\n')
                    file.write('target_include_directories('+service["name"]+' PUBLIC\n\t${USR_INCLUDE_DIR}\n)\nendif()\n\n')
                    file.write('target_compile_definitions({service_name} PUBLIC\n$<$<CONFIG:Debug>: -DDEBUG -D_DEBUG>\n$<$<CONFIG:Release>: -DRELEASE>\n)\n'.format(service_name=service["name"]))

                    if platform.system() == "Windows":
                        file.write('target_link_libraries(' + service["name"] + ' PUBLIC \n')
                        file.write(
                            '"$<$<AND:$<CONFIG:Release>,$<BOOL:${USR_LINK_RELEASE_LIB}>>:${USR_LINK_RELEASE_LIB}>"\n"$<$<AND:$<CONFIG:Debug>,$<BOOL:${USR_DEBUG_LINK_LIB}>>:${USR_DEBUG_LINK_LIB}>"\n' +
                            'debug ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/debug/libprotobufd.lib optimized ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/release/libprotobuf.lib\n' 
                            )                        
                    else:
                        file.write('target_link_libraries(' + service["name"] + ' PUBLIC \n')
                        file.write(
                            '\t"$<$<BOOL:${USR_LINK_LIB}>:${USR_LINK_LIB}>"\n' + 
                            '\t${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/linux/libprotobuf.a\n'
                        )
                    file.write(')\n')
                    if service["loadType"] == "dynamic":
                        if platform.system() == "Windows":
                            file.write('target_link_libraries(' + service["name"] + '_module PUBLIC \n')
                            file.write('debug ${PROJECT_SOURCE_DIR}/../../../../lib/root/debug/librpc.a optimized ${PROJECT_SOURCE_DIR}/../../../../lib/root/release/librpc.a\n')
                            file.write('debug ${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/debug/lib'+base_name+'.a optimized ${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/release/lib'+base_name+'.a\n')
                            file.write('debug ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/debug/libprotobufd.lib optimized ${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/windows/release/libprotobuf.lib\n')
                        else:
                            file.write('target_link_libraries(' + service["name"] + '_module PUBLIC \n')
                            file.write('\t${PROJECT_SOURCE_DIR}/../../../../lib/root/librpc.a\n')
                            file.write('\t${PROJECT_SOURCE_DIR}/../../../../lib/'+base_name+'/lib'+base_name+'.a\n')
                            file.write('\t${PROJECT_SOURCE_DIR}/../../../../thirdparty/lib/linux/libprotobuf.a\n')
                        file.write(')\n')
                    file.close()
                    if platform.system() == "Windows":
                        os.system('cmake -G  "Visual Studio 16 2019" -A x64')
                        os.system('cmake --build . --config "Release"')
                        os.system('cmake --build . --config "Debug"')
                    else:
                        os.system("cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ .")
                        os.system("make")
                os.chdir("../../")
        os.chdir("../../")

    def beforCreate(self, file_name, sname, add):
        (base_name, _) = os.path.splitext(os.path.basename(file_name))
        json_str = json.load(open(base_name + ".idl.cpp.json"))
        if ("serviceNames" in json_str) and (json_str["serviceNames"] is not None):
            for service_name in json_str["serviceNames"]:
                if sname is not None:
                    if sname != service_name:
                        continue
                file_name = "../../usr/impl/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".impl.h"
                if not os.path.exists(file_name):
                    continue
                shutil.move(file_name, base_name + ".service." + service_name + ".impl.h")

    # @title 构建测试server 用于测试
    def build_beta_server(self, file_name, sname=None):
        # 检查服务 是否被编译
        file_name = os.path.basename(file_name)
        file_name = file_name.split('.')[0]
        if not os.path.exists('./src/idl/' + file_name + '.idl'):
            print('[Error] idl ', file_name, "not import yet !!!!")
            return False

        json_str = json.load(open('./src/idl/' + file_name + ".idl.cpp.json"))
        if not json_str:
            print('[Error] open idl descript file error !!')
            return False
        
        # idl 没有service 我生成个蛋蛋锤 
        if not json_has_attr(json_str, 'services'):
            print('[Info] idl {file_name} not contains any service '.format(file_name=file_name))
            return True

        depst = {}
        if json_has_attr(json_str, 'structNames'):
            depst = json_str['structNames']

        depen = None
        if json_has_attr(json_str, 'enumNames'):
            depen= json_str['enumNames']
        
        for service in json_str["services"]:
            if (sname is not None) and (sname != service["name"]):
                continue

            # 准备豪必要的 变量
            uuid = service['uuid']
            service_name = service['name']

            is_dynamic = (service['loadType'] == 'dynamic')
            # 检查依赖中间文件 比如dll 和 .a 这种文件
            if not check_service_build(file_name, service_name, is_dynamic):
                print('[Error] service:{sname} in {file_name}.idl not build yet'.format(sname=service_name, file_name=file_name))
                return False
            
            # 检查需要的目录 准备生成工程
            # 检查必要目录 tmp/idlname/test/service_name/proxy or server 如果目录存在说明生成过了 不存在就新建
            test_path = './tmp/{idl_name}/test/{service_name}/proxy'.format(idl_name=file_name, service_name=service_name)
            if not os.path.exists(test_path):
                print('Mock dir {name} not exit'.format(name=test_path))
                os.makedirs(test_path)

            # 拷贝thirdparty 过去反正没有多大懒得改工程CMake结构了
            if not os.path.exists(test_path + '/thirdparty'):
                shutil.copytree('./mock/cmock/thirdparty', test_path+'/thirdparty')

            # 生成 proxy 相关的文件 还有CMake
            try:
                gen_test_proxy(test_path, file_name, service_name, service['methods'], depst, depen)
            except Exception as err:
                print('[Error] generate server test project caller error {0} {1}'.format(err, err.args))
                return False

            # 读取server template 生成serve.cpp cmakelist 拷贝transport
            test_path = './tmp/{idl_name}/test/{service_name}/server'.format(idl_name=file_name, service_name=service_name)
            if not os.path.exists(test_path):
                print('Mock dir {name} not exit'.format(name=test_path))
                os.makedirs(test_path)

            # 拷贝thirdparty 过去反正没有多大懒得改工程CMake结构了
            if not os.path.exists(test_path+'/thirdparty'):
                shutil.copytree('./mock/cmock/thirdparty', test_path + '/thirdparty')

            try:
                # 生成server.cpp
                if is_dynamic:
                    genfile = open(test_path+'/server.cpp', 'w')
                    tfile = open('./mock/template/dynamic_server.template', 'r').read()
                    server_template = Template(tfile)
                    genfile.write(server_template.substitute(base_name=file_name, service_name=service_name, uuid=uuid))
                    genfile.close()
                else:
                    shutil.copyfile('./mock/template/static_server.template', test_path+'/server.cpp')

                #拷贝mock trans port
                shutil.copyfile('./mock/cmock/src/mock_transport.h', test_path + '/mock_transport.h')
                shutil.copyfile('./mock/cmock/src/mock_transport.cpp', test_path + '/mock_transport.cpp')
                shutil.copyfile('./mock/cmock/src/mock_logger.h', test_path + '/mock_logger.h')

                # 生成 cmakelist
                tcmake = None
                if is_dynamic:
                    tcmake = Template(open('./mock/template/server_cmake_dynamic.template', 'r').read())
                else:
                    tcmake = Template(open('./mock/template/server_cmake_static.template', 'r').read())

                gen_cmake = open(test_path+'/CMakeLists.txt', 'w')
                gen_cmake.write(tcmake.substitute(base_name=file_name, service_name=service_name, execname=service_name.lower()))
                gen_cmake.close()
            except Exception as err:
                print('[Error] generate server test project error {0}'.format(err))
                return False


    def do_lua_template(self, base_name, service_name, idl_name):
        lua_impl_h_file_path = "../../usr/impl/" + base_name + "/" + idl_name + '/' + base_name + '.service.' + service_name + '.impl.h'
        hpp_replace_file_name = base_name + '.service.' + service_name + '.h'
        shutil.copyfile("../../usr/lua_template/lua_service_template.h", lua_impl_h_file_path)

        hpp_template = Template(open("../../usr/lua_template/lua_template_hpp.template", 'r').read())
        hpp_file = open(lua_impl_h_file_path, 'w')
        hpp_file.write(hpp_template.substitute(service_name=service_name, head_file=hpp_replace_file_name))

        lua_impl_file_path = "../../usr/impl/" + base_name + "/" + idl_name + '/' + base_name + '.service.' + service_name + '.cpp'
        cpp_replace_file_name = base_name + '.service.' + service_name + '.impl.h'
        shutil.copyfile("../../usr/lua_template/lua_service_template.cpp", lua_impl_file_path)

        cpp_template = Template(open("../../usr/lua_template/lua_template_cpp.template", 'r').read())
        cpp_file = open(lua_impl_file_path, 'w')
        cpp_file.write(cpp_template.substitute(service_name=service_name, head_file=cpp_replace_file_name))

    def addIdl2Repo(self, file_name, sname=None, add=True):
        if not add:
            file_name = "src/idl/" + file_name
        if not os.path.exists(file_name):
            print(file_name + " not found")
            return
        file_name = self.check_idl_name(file_name)

        # 递归处理idl import 依赖文件
        idl_list = deal_idl_import(file_name)

        # 递归拷贝所有idl依赖文件
        # 拷贝idl并生成对应的文件和文件夹 src/idl 目录下 保持原有目录一致
        if add:
            copy_dep_idl(os.path.dirname(file_name), idl_list, 'src/idl')
            shutil.copyfile(file_name, './src/idl/' + os.path.basename(file_name))

        os.chdir("src/idl/")
        cmd = subprocess.Popen(["../../bin/rpc-frontend", "-f", os.path.basename(file_name)], stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        ret = cmd.communicate()
        if cmd.returncode != 0:
            print(ret[1])
            return

        self.beforCreate(file_name, sname, add)

        # gen proxy and stub files
        cmd = subprocess.Popen(["python", "../../bin/cppgen.py", os.path.basename(file_name) + ".cpp.json"],
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        ret = cmd.communicate()
        if cmd.returncode != 0:
            print("cppgen.py failed")
            print(ret[1])
            return
        
        # gen sdk files
        cmd = subprocess.Popen(["python", "../../bin/cppgen_sdk.py", os.path.basename(file_name) + ".cpp.json"],
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)        
        ret = cmd.communicate()
        if cmd.returncode != 0:
            print("cppgen_sdk.py failed")
            print(ret[1])
            return
        
        # gen PB files
        cmd = subprocess.Popen(["python", "../../bin/cppgen_pb_layer.py", os.path.basename(file_name) + ".cpp.json",
                                os.path.basename(file_name) + ".protobuf.json"], stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        ret = cmd.communicate()
        if cmd.returncode != 0:
            print("cppgen_pb_layer.py failed")
            print(ret[1])
            return
        (base_name, _) = os.path.splitext(os.path.basename(file_name))
        json_str = json.load(open(base_name + ".idl.cpp.json"))
        
        if not os.path.exists("../include/" + base_name + "/protobuf"):
            os.makedirs("../include/" + base_name + "/protobuf")
        if not os.path.exists("../" + base_name + "/protobuf"):
            os.makedirs("../" + base_name + "/protobuf")

        if json_has_attr(json_str, "structs"):
            shutil.copyfile(base_name + ".struct.h", "../include/" + base_name + "/" + base_name + ".struct.h")
            orm_h_path = base_name + '.orm.h'
            orm_cpp_path = base_name +'.orm.cpp'
            if os.path.exists(orm_h_path):
                shutil.copyfile(orm_h_path, "../include/" + base_name + "/" + orm_h_path)
            shutil.copyfile(orm_cpp_path, "../" + base_name + "/" + orm_cpp_path)

            for struct_name in json_str["structNames"]:
                shutil.copyfile(struct_name + "_struct.h", "../include/" + base_name + "/" + struct_name + "_struct.h")


        if json_has_attr(json_str, "enums"):
            shutil.copyfile(base_name + ".enum.h", "../include/" + base_name + "/" + base_name + ".enum.h")


        if json_has_attr(json_str, "serviceNames"):        
            for service_name in json_str["serviceNames"]:
                if sname is not None:
                    if sname != service_name:
                        continue
                if not os.path.exists("../include/" + base_name + "/" + service_name + "/proxy"):
                    os.makedirs("../include/" + base_name + "/" + service_name + "/proxy")
                if not os.path.exists("../include/" + base_name + "/" + service_name + "/stub"):
                    os.makedirs("../include/" + base_name + "/" + service_name + "/stub")
                if not os.path.exists("../proxy/" + base_name + "/" + service_name):
                    os.makedirs("../proxy/" + base_name + "/" + service_name)
                if not os.path.exists("../stub/" + base_name + "/" + service_name):
                    os.makedirs("../stub/" + base_name + "/" + service_name)
                if not os.path.exists("../../usr/impl/" + base_name + "/" + service_name):
                    os.makedirs("../../usr/impl/" + base_name + "/" + service_name)
                shutil.copyfile(base_name + ".service." + service_name + ".h",
                                "../include/" + base_name + "/" + base_name + ".service." + service_name + ".h")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.h",
                                "../include/" + base_name + "/" + service_name + "/proxy/" + base_name + '.service.' + service_name + ".proxy.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.sdk.h",
                                "../include/" + base_name + "/" + service_name + "/proxy/" + base_name + '.service.' + service_name + ".proxy.sdk.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.serializer.h",
                                "../include/" + base_name + "/" + service_name + "/proxy/" + base_name + '.service.' + service_name + ".proxy.serializer.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.serializer.sdk.h",
                                "../include/" + base_name + "/" + service_name + "/proxy/" + base_name + '.service.' + service_name + ".proxy.serializer.sdk.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.cpp",
                                "../proxy/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".proxy.cpp")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.sdk.cpp",
                                "../proxy/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".proxy.sdk.cpp")
                shutil.copyfile(base_name + '.service.' + service_name + ".proxy.serializer.cpp",
                                "../proxy/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".proxy.serializer.cpp")
                shutil.copyfile(base_name + '.service.' + service_name + ".stub.h",
                                "../include/" + base_name + "/" + service_name + "/stub/" + base_name + '.service.' + service_name + ".stub.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".stub.serializer.h",
                                "../include/" + base_name + "/" + service_name + "/stub/" + base_name + '.service.' + service_name + ".stub.serializer.h")
                shutil.copyfile(base_name + '.service.' + service_name + ".stub.cpp",
                                "../stub/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".stub.cpp")
                shutil.copyfile(base_name + '.service.' + service_name + ".stub.serializer.cpp",
                                "../stub/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".stub.serializer.cpp")
                if not os.path.exists("../../../../sdk_unittest/src/test/" + base_name + '.' + service_name + ".unittest.cpp"):
                    if os.path.exists(base_name + '.' + service_name + ".unittest.cpp") and os.path.exists("../../../../sdk_unittest/src/test/"):
                        shutil.copyfile(base_name + '.' + service_name + ".unittest.cpp",
                                        "../../../../sdk_unittest/src/test/" + base_name + '.' + service_name + ".unittest.cpp")
                
                shutil.move(base_name + ".service." + service_name + ".impl.h",
                                "../../usr/impl/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".impl.h")
                if not os.path.exists(
                        "../../usr/impl/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".cpp"):
                    shutil.copyfile(base_name + '.service.' + service_name + ".cpp",
                                    "../../usr/impl/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".cpp")
                self.genImplCmake(base_name, service_name, "../../usr/impl/"+base_name+"/"+service_name)

        if ("services" in json_str) and (json_str["services"] is not None):
            for service in json_str["services"]:
                if sname is not None:
                    if sname != service["name"]:
                        continue
                if service["loadType"] == "dynamic":
                    service_name = service["name"]
                    shutil.copyfile(base_name + '.service.' + service_name + ".so.h",
                                    "../include/" + base_name + "/" + service_name + "/stub/" + base_name + '.service.' + service_name + ".so.h")
                    shutil.copyfile(base_name + '.service.' + service_name + ".so.cpp",
                                    "../stub/" + base_name + "/" + service_name + "/" + base_name + '.service.' + service_name + ".so.cpp")
                if service['type'] == 'generic':
                    if service["notations"] is None:
                        continue
                    is_lua = False
                    for notation in service["notations"]:
                        if notation["script_type"] is not None:
                            for script_type in notation["script_type"]:
                                if script_type == "lua":
                                    is_lua = True
                    if not is_lua:
                        continue
                    if not os.path.exists("../../usr/impl/" + base_name + "/" + service['name']):
                        os.makedirs("../../usr/impl/" + base_name + "/" + service['name'])
                    self.do_lua_template(base_name, service_name, service['name'])
        
        if os.path.exists(base_name + '.service.pb.h'):
            shutil.copyfile(base_name + '.service.pb.h',
                            "../include/" + base_name + "/protobuf/" + base_name + '.service.pb.h')

        if os.path.exists(base_name + '.service.pb.cc'):
            shutil.copyfile(base_name + '.service.pb.cc', "../" + base_name + "/protobuf/" + base_name + '.service.pb.cc')

        remove_files(".", "*.h")
        remove_files(".", "*.cpp")
        remove_files(".", "*.cc")
        #remove_files(".", "*.proto")
        os.chdir("../../")

    def updateRoot(self):
        initializer = Initializer_cpp(Options())
        initializer.inspectpath()
        os.chdir("tmp/rpc-frontend/")
        os.system('git pull origin')
        os.chdir("..")
        initializer.build_frontend()
        os.chdir("..")
        os.chdir("tmp/rpc-backend-cpp/")
        os.system('git pull origin')
        os.chdir("..")
        initializer.build_backend()
        os.chdir("../../")

    def genImplCmake(self, base_name, service_name, target_path):
        if os.path.exists(target_path+'/CMakeLists.txt'):
            return True
        
        file = open(target_path+"/CMakeLists.txt", "w")
        file.write('cmake_minimum_required(VERSION 3.10)\n')
        file.write('#generated_code_begin\n\n')
        file.write('set(SERVICE_DIR ${PROJECT_SOURCE_DIR}/../../../..)\n')
        file.write('file(GLOB USR_IMPL_SRC ${SERVICE_DIR}/usr/impl/' + base_name + '/' + service_name + '/*.cpp)\n')

        file.write('set(USR_INCLUDE_DIR ${SERVICE_DIR}/usr/impl/' + base_name + '/' + service_name + ')\n')
        if platform.system() == "Windows":
            file.write('set(USR_DEBUG_LINK_LIB ${SERVICE_DIR}/lib/'+ base_name + '/Debug/lib' + base_name +'.a)\n')
            file.write('set(USR_LINK_RELEASE_LIB ${SERVICE_DIR}/lib/'+ base_name + '/Release/lib' + base_name +'.a)\n')
        elif platform.system() == "Linux": 
            file.write('set(USR_LINK_LIB ${SERVICE_DIR}/lib/' + base_name + '/lib' + base_name + '.a)\n')
        file.write('#generated_code_end\n\n')
        
        file.write('\n#add you own code here\n')
        file.write('#append your own include dir by\n#list(APPEND USR_INCLUDE_DIR your_include_dir)\n#append your own source file by\n#list(APPEND USR_IMPL_SRC your_source_file)\n')
        if platform.system() == "Windows":
            file.write('#append debug lib \n#list(APPEND USR_DEBUG_LINK_LIB debuglib)\n#append release lib\n #list(APPEND USR_LINK_RELEASE_LIB releaselib)\n')
        elif platform.system() == "Linux":
            file.write('#append your own thirdparty dir by \n#list(APPEND USR_LINK_DIR your_own_link_dir)\n')
            file.write('#append your own universal linklib, not difference between debug mode and release mode\n#list(APPEND USR_LINK_LIB universallib)\n')

        file.write('#end\n')

        return True

